﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Core
{
    public class ItemContainer : Entity, IAwake<Unit, string, int>
    {
        private readonly List<ItemSlot> slots = new List<ItemSlot>();

        public Unit Owner { get; private set; }
        public IReadOnlyList<ItemSlot> Slots => slots;

        public int Count => slots.Count;

        public string Key { get; private set; }
        
        public ItemSlot this[int index] 
        {
            get
            {
                if (index < 0 || index >= slots.Count)
                    return default;

                return slots[index];
            }
        }

        void IAwake<Unit, string, int>.Awake(Unit unit, string key, int num)
        {
            Owner = unit;
            this.Key = key;
            for (int i = 0; i < num; i++)
            {
                slots.Add(new ItemSlot(this, i));
            }
        }

        public int CanAddItemCount(int itemId)
        {
            var config = World.GetComponent<ConfigComponent>().GetConfig<ItemConfig>(itemId);
            if (config == null)
                return 0;

            int canAddCount = 0;
            foreach (var slot in slots)
            {
                if (slot.itemId == itemId)
                    canAddCount += (config.maxStackSize - slot.count);
                else if (slot.itemId == 0)
                    canAddCount += config.maxStackSize;
            }

            return canAddCount;
        }

        public int AddItem(int itemId, int count)
        {
            var config = World.GetComponent<ConfigComponent>().GetConfig<ItemConfig>(itemId);
            if (config == null)
                return 0;

            foreach (var slot in slots)
            {
                if (slot.itemId != itemId)
                    continue;

                if (slot.count + count > config.maxStackSize)
                {
                    int change = config.maxStackSize - slot.count;
                    if (change > 0)
                    {
                        count -= change;
                        slot.UpdateCount(change);
                    }
                }
                else
                {
                    if (count > 0)
                    {
                        slot.UpdateCount(count);
                        count = 0;
                    }
                    break;
                }
            }

            if (count <= 0)
            {
                return 0;
            }

            int itemInstnceId = 0;
            var containerMgr = this.GetParent<ItemContainerMgr>();
            foreach (var slot in slots)
            {
                if (slot.itemId != 0)
                    continue;
                if (count > config.maxStackSize)
                {
                    count -= config.maxStackSize;
                    itemInstnceId = containerMgr.GenerateItemID();
                    slot.UpdateItemByInstId(itemInstnceId, itemId, config.maxStackSize);
                }
                else
                {
                    if (count > 0)
                    {
                        itemInstnceId = containerMgr.GenerateItemID();
                        slot.UpdateItemByInstId(itemInstnceId, itemId, count);
                    }
                    break;
                }
            }

            return itemInstnceId;
        }

        public bool RemoveItem(int itemId, int count)
        {
            foreach (var slot in slots)
            {
                if (slot.itemId != itemId)
                    continue;

                if (slot.count < count)
                {
                    count -= slot.count;
                    slot.UpdateCount(-slot.count);
                }
                else
                {
                    if (count > 0)
                    {
                        slot.UpdateCount(-count);
                    }
                    count = 0;
                    break;
                }
            }
            return count == 0;
        }

        public ItemSlot GetItemSlot(int instID)
        {
            foreach (var slot in slots)
            {
                if (slot.instanceId == instID)
                    return slot;
            }
            return default;
        }

        public IReadOnlyList<ItemSlot> GetItemSlots(int itemId)
        {
            List<ItemSlot> result = new List<ItemSlot>();
            foreach (var slot in slots)
            {
                if(slot.itemId == itemId)
                {
                    result.Add(slot);
                }
            }
            return result;
        }

        public int GetItemCount(int itemId)
        {
            int count = 0;
            foreach (var slot in slots)
            {
                if (slot.itemId == itemId)
                {
                    count += slot.count;
                }
            }
            return count;
        }

        public void Clear()
        {
            foreach (var slot in slots)
            {
                slot.Clear();
            }
        }

        public void Resize(int size)
        {
            var num = size - slots.Count;
            if(num > 0)
            {
                for (int i = 0; i < num; i++)
                {
                    slots.Add(new ItemSlot(this, slots.Count));
                }
            }
            else
            {
                num = Math.Abs(num);
                if (num == 0)
                    return;
                for (int i = 0; i < num; i++)
                {
                    slots.RemoveAt(slots.Count - 1);
                }
            }
        }
    }
}
